package com.example.demo2.config;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * HttpClient 配置
 *
 * @author wuh
 */
@Slf4j
@Configuration
public class HttpClientConfig {

  /**
   * 最大连接数
   */
  @Value("${http.max-total:1000}")
  private Integer maxTotal;

  /**
   * 同路由并发数
   */
  @Value("${http.default-Max-Per-Route:800}")
  private Integer defaultMaxPerRoute;

  /**
   * 连接超时时间
   */
  @Value("${http.connect-timeout:2000}")
  private Integer connectTimeout;

  /**
   * 从连接池中获取到连接的最长时间
   */
  @Value("${http.connection-request-timeout:1000}")
  private Integer connectionRequestTimeout;

  /**
   * 数据传输的最长时间
   */
  @Value("${http.socket-timeout:60000}")
  private Integer socketTimeout;

  @Bean("httpClientConnectionManager")
  public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
    PoolingHttpClientConnectionManager httpClientConnectionManager;
    try {
      SSLContext sslContext = new SSLContextBuilder()
          .loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true).build();
      HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
      SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
          sslContext, hostnameVerifier);
      Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
          .<ConnectionSocketFactory>create()
          .register("http", PlainConnectionSocketFactory.getSocketFactory())
          .register("https", sslConnectionSocketFactory).build();// 注册http和https请求
      httpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    } catch (Exception e) {
      log.error("Error: Generate PoolingHttpClientConnectionManager failed!", e);
      httpClientConnectionManager = new PoolingHttpClientConnectionManager();
    }

    httpClientConnectionManager.setMaxTotal(maxTotal);
    httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
    return httpClientConnectionManager;
  }

  @Bean(name = "httpClientBuilder")
  public HttpClientBuilder getHttpClientBuilder(
      @Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    httpClientBuilder.setConnectionManager(httpClientConnectionManager);
    return httpClientBuilder;
  }

  @Bean
  @Primary
  public CloseableHttpClient getCloseableHttpClient(
      @Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
    return httpClientBuilder.build();
  }

  @Bean
  public RequestConfig.Builder getBuilder() {
    RequestConfig.Builder builder = RequestConfig.custom();
    return builder.setConnectTimeout(connectTimeout)
        .setConnectionRequestTimeout(connectionRequestTimeout)
        .setSocketTimeout(socketTimeout);
  }

  @Bean
  public RequestConfig getRequestConfig(RequestConfig.Builder builder) {
    return builder.build();
  }

}
